from typing import Dict, List, Callable, Any
import logging
import threading
import pickle
import socket
import select
import time

logger = logging.getLogger("EventSystem")

class EventSystem:
    """事件系统 - 用于组件间通信
    
    特性:
    - 支持事件订阅和发布
    - 支持异步事件处理
    - 支持事件优先级
    """
    
    def __init__(self):
        self._subscribers: Dict[str, List[tuple]] = {}
        self._lock = threading.Lock()
    
    def subscribe(self, event_name: str, callback: Callable, priority: int = 0) -> None:
        """订阅事件
        
        Args:
            event_name: 事件名称
            callback: 回调函数，接收事件数据作为参数
            priority: 优先级，数字越大优先级越高
        """
        with self._lock:
            if event_name not in self._subscribers:
                self._subscribers[event_name] = []
            
            # 添加订阅者并按优先级排序
            self._subscribers[event_name].append((callback, priority))
            self._subscribers[event_name].sort(key=lambda x: x[1], reverse=True)
            
            logger.debug(f"已订阅事件 '{event_name}'，当前订阅者数量: {len(self._subscribers[event_name])}")
    
    def unsubscribe(self, event_name: str, callback: Callable) -> bool:
        """取消订阅事件
        
        Args:
            event_name: 事件名称
            callback: 要取消的回调函数
            
        Returns:
            bool: 是否成功取消订阅
        """
        with self._lock:
            if event_name not in self._subscribers:
                return False
            
            # 查找并移除订阅者
            initial_count = len(self._subscribers[event_name])
            self._subscribers[event_name] = [
                (cb, priority) for cb, priority in self._subscribers[event_name] 
                if cb != callback
            ]
            
            # 如果没有订阅者，删除事件
            if not self._subscribers[event_name]:
                del self._subscribers[event_name]
            
            removed = len(self._subscribers.get(event_name, [])) < initial_count
            if removed:
                logger.debug(f"已取消订阅事件 '{event_name}'")
            
            return removed
    
    def publish(self, event_name: str, data: Any = None) -> None:
        """发布事件
        
        Args:
            event_name: 事件名称
            data: 事件数据
        """
        subscribers = []
        
        # 获取订阅者列表（使用锁保护）
        with self._lock:
            if event_name in self._subscribers:
                subscribers = self._subscribers[event_name].copy()
        
        if not subscribers:
            logger.debug(f"事件 '{event_name}' 没有订阅者")
            return
        
        logger.debug(f"发布事件 '{event_name}'，订阅者数量: {len(subscribers)}")
        
        # 调用所有订阅者的回调函数
        for callback, _ in subscribers:
            try:
                callback(data)
            except Exception as e:
                logger.error(f"处理事件 '{event_name}' 时出错: {str(e)}")
    
    def publish_async(self, event_name: str, data: Any = None) -> None:
        """异步发布事件
        
        Args:
            event_name: 事件名称
            data: 事件数据
        """
        thread = threading.Thread(
            target=self.publish,
            args=(event_name, data),
            daemon=True
        )
        thread.start()
    
    def clear_all(self) -> None:
        """清除所有订阅"""
        with self._lock:
            self._subscribers.clear()
            logger.debug("已清除所有事件订阅")

class IPCEventSystem:
    """跨进程事件系统 - 用于进程间通信
    
    特性:
    - 支持跨进程事件发布和订阅
    - 使用 TCP socket 进行通信
    - 支持事件序列化和反序列化
    """
    
    DEFAULT_HOST = '127.0.0.1'
    DEFAULT_PORT = 9876
    BUFFER_SIZE = 4096
    
    def __init__(self, is_server: bool = True, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT):
        """初始化跨进程事件系统
        
        Args:
            is_server: 是否作为服务器端运行
            host: 服务器主机地址
            port: 服务器端口
        """
        self.is_server = is_server
        self.host = host
        self.port = port
        self._subscribers: Dict[str, List[tuple]] = {}
        self._lock = threading.Lock()
        self._running = False
        self._socket = None
        self._clients = []
        self._local_event_system = EventSystem()  # 本地事件系统
        
    def start(self):
        """启动事件系统"""
        if self._running:
            return
            
        self._running = True
        
        if self.is_server:
            self._start_server()
        else:
            self._connect_to_server()
            
    def _start_server(self):
        """启动服务器"""
        try:
            self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self._socket.bind((self.host, self.port))
            self._socket.listen(5)
            self._socket.setblocking(False)
            
            logger.info(f"IPC事件服务器已启动，监听 {self.host}:{self.port}")
            
            # 启动接收线程
            threading.Thread(target=self._server_loop, daemon=True).start()
        except Exception as e:
            logger.error(f"启动IPC事件服务器失败: {str(e)}")
            self._running = False
            
    def _connect_to_server(self):
        """连接到服务器"""
        try:
            self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self._socket.connect((self.host, self.port))
            
            logger.info(f"已连接到IPC事件服务器 {self.host}:{self.port}")
            
            # 启动接收线程
            threading.Thread(target=self._client_loop, daemon=True).start()
        except Exception as e:
            logger.error(f"连接到IPC事件服务器失败: {str(e)}")
            self._running = False
            
    def _server_loop(self):
        """服务器循环"""
        while self._running:
            try:
                readable, _, _ = select.select([self._socket] + self._clients, [], [], 0.1)
                
                for sock in readable:
                    if sock is self._socket:
                        # 新客户端连接
                        client, addr = self._socket.accept()
                        self._clients.append(client)
                        logger.debug(f"新客户端连接: {addr}")
                    else:
                        # 客户端数据
                        try:
                            data = sock.recv(self.BUFFER_SIZE)
                            if data:
                                # 处理接收到的事件
                                self._handle_received_data(data)
                                
                                # 转发给其他客户端
                                for client in self._clients:
                                    if client != sock:
                                        try:
                                            client.send(data)
                                        except:
                                            pass
                            else:
                                # 客户端断开连接
                                sock.close()
                                self._clients.remove(sock)
                        except:
                            # 客户端异常
                            try:
                                sock.close()
                                self._clients.remove(sock)
                            except:
                                pass
            except Exception as e:
                logger.error(f"IPC服务器循环异常: {str(e)}")
                time.sleep(0.1)
                
    def _client_loop(self):
        """客户端循环"""
        while self._running:
            try:
                readable, _, _ = select.select([self._socket], [], [], 0.1)
                
                if self._socket in readable:
                    data = self._socket.recv(self.BUFFER_SIZE)
                    if data:
                        # 处理接收到的事件
                        self._handle_received_data(data)
                    else:
                        # 服务器断开连接
                        logger.warning("IPC事件服务器断开连接")
                        self._running = False
                        break
            except Exception as e:
                logger.error(f"IPC客户端循环异常: {str(e)}")
                self._running = False
                break
                
    def _handle_received_data(self, data):
        """处理接收到的数据"""
        try:
            event_data = pickle.loads(data)
            event_name = event_data.get('event_name')
            event_payload = event_data.get('data')
            
            if event_name:
                # 在本地触发事件
                self._local_event_system.publish(event_name, event_payload)
        except Exception as e:
            logger.error(f"处理IPC事件数据失败: {str(e)}")
            
    def stop(self):
        """停止事件系统"""
        self._running = False
        
        # 关闭所有连接
        if self.is_server:
            for client in self._clients:
                try:
                    client.close()
                except:
                    pass
            self._clients = []
            
        # 关闭socket
        if self._socket:
            try:
                self._socket.close()
            except:
                pass
            self._socket = None
            
        logger.info("IPC事件系统已停止")
        
    def subscribe(self, event_name: str, callback: Callable, priority: int = 0) -> None:
        """订阅事件
        
        Args:
            event_name: 事件名称
            callback: 回调函数，接收事件数据作为参数
            priority: 优先级，数字越大优先级越高
        """
        # 使用本地事件系统处理订阅
        self._local_event_system.subscribe(event_name, callback, priority)
        
    def unsubscribe(self, event_name: str, callback: Callable) -> bool:
        """取消订阅事件
        
        Args:
            event_name: 事件名称
            callback: 要取消的回调函数
            
        Returns:
            bool: 是否成功取消订阅
        """
        # 使用本地事件系统处理取消订阅
        return self._local_event_system.unsubscribe(event_name, callback)
        
    def publish(self, event_name: str, data: Any = None) -> None:
        """发布事件（跨进程）
        
        Args:
            event_name: 事件名称
            data: 事件数据（必须可序列化）
        """
        # 先在本地发布
        self._local_event_system.publish(event_name, data)
        
        # 然后发送到其他进程
        if self._socket and self._running:
            try:
                # 序列化事件数据
                event_data = {
                    'event_name': event_name,
                    'data': data
                }
                serialized_data = pickle.dumps(event_data)
                
                if self.is_server:
                    # 服务器发送给所有客户端
                    for client in self._clients:
                        try:
                            client.send(serialized_data)
                        except:
                            pass
                else:
                    # 客户端发送给服务器
                    self._socket.send(serialized_data)
            except Exception as e:
                logger.error(f"发布IPC事件失败: {str(e)}")
                
    def publish_async(self, event_name: str, data: Any = None) -> None:
        """异步发布事件
        
        Args:
            event_name: 事件名称
            data: 事件数据
        """
        thread = threading.Thread(
            target=self.publish,
            args=(event_name, data),
            daemon=True
        )
        thread.start()
        
    def clear_all(self) -> None:
        """清除所有订阅"""
        self._local_event_system.clear_all()

# 创建进程间通信辅助函数
def create_ipc_event_system(is_server: bool = True, host: str = IPCEventSystem.DEFAULT_HOST, 
                           port: int = IPCEventSystem.DEFAULT_PORT) -> IPCEventSystem:
    """创建跨进程事件系统
    
    Args:
        is_server: 是否作为服务器端运行
        host: 服务器主机地址
        port: 服务器端口
        
    Returns:
        IPCEventSystem: 跨进程事件系统实例
    """
    ipc_system = IPCEventSystem(is_server, host, port)
    ipc_system.start()
    return ipc_system

# 全局事件系统实例
event_system = EventSystem()

# 预定义事件名称
class Events:
    """预定义事件名称"""
    # 系统事件
    STARTUP = "system.startup"
    SHUTDOWN = "system.shutdown"
    CONFIG_CHANGED = "system.config_changed"
    
    # 连接事件
    CONNECTION_ESTABLISHED = "connection.established"
    CONNECTION_LOST = "connection.lost"
    CONNECTION_ERROR = "connection.error"
    
    # 命令事件
    COMMAND_RECOGNIZED = "command.recognized"
    COMMAND_EXECUTED = "command.executed"
    COMMAND_FAILED = "command.failed"
    
    # UI事件
    UI_NOTIFICATION = "ui.notification" #悬浮窗提示
    
    # 会议记录
    MEETING_RECORD = "meeting.record"
    
    # 进程间通信事件
    IPC_CONNECTED = "ipc.connected"
    IPC_DISCONNECTED = "ipc.disconnected"
    IPC_ERROR = "ipc.error"
    IPC_MESSAGE = "ipc.message"
    
class EventNames:
    """事件名称列表"""
    RECORD_CREATED = "record.create"
    RECORD_EXIT = "record.exit"
    RECORD_ADD = "record.add"
    RECORD_STOP = "record.stop"
    RECORD_START = "record.start"
    RECORD_SUM = "record.sum"
    
    WEATHER = "weather"
